home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / C / Games / Xconq 7.1.0 / src / xconq-7.1.0 / kernel / mkrivers.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-07-07  |  8.1 KB  |  301 lines  |  [TEXT/R*ch]

  1. /* River generation for Xconq.
  2.    Copyright 1991, 1992, 1993, 1994, 1995, 1996 Stanley T. Shebs.
  3.  
  4. Xconq is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2, or (at your option)
  7. any later version.  See the file COPYING.  */
  8.  
  9. /* This river generator requires elevations. */
  10.  
  11. #include "conq.h"
  12.  
  13. static void make_up_river_borders PARAMS ((int rivertype));
  14. static int border_is_compatible PARAMS ((int x, int y, int dir, int b));
  15. static int elev_in_dir PARAMS ((int x, int y, int dir));
  16. static int elev_at_meet PARAMS ((int x, int y, int dir));
  17. static void set_river_at PARAMS ((int x, int y, int dir, int t));
  18. static void make_up_river_connections PARAMS ((int rivertype));
  19.  
  20. static int totalrivers;
  21.  
  22. /* Add rivers by picking a headwater randomly, then running downhill. */
  23.  
  24. /* Can do as either a border or connection type, depending on which
  25.    terrain type is called "river". */
  26.  
  27. int
  28. make_rivers(calls, runs)
  29. int calls, runs;
  30. {
  31.     int x, y, t;
  32.  
  33.     totalrivers = 0;
  34.     for_all_interior_cells(x, y) {
  35.     totalrivers += t_river_chance(terrain_at(x, y));
  36.     }
  37.     if (totalrivers <= 0)
  38.       return FALSE;
  39.     totalrivers /= 10000;
  40.     totalrivers = max(1, totalrivers);
  41.     if (elevations_defined()) {
  42.     for_all_terrain_types(t) {
  43.         if (t_subtype_x(t) == 10 /*keyword_value(K_RIVER_X)*/
  44.         && !aux_terrain_defined(t)) {
  45.         if (t_is_border(t)) {
  46.             make_up_river_borders(t);
  47.         } else if (t_is_connection(t)) {
  48.             make_up_river_connections(t);
  49.         }
  50.         }
  51.     }
  52.     }
  53.     return TRUE;
  54. }
  55.  
  56. static int touchedwater;
  57.  
  58. /* Turn this on to record (as features) information about rivers
  59.    are being constructed. */
  60.  
  61. static int DebugRiver = FALSE;
  62.  
  63. /* (should reindent) */
  64. static void
  65. make_up_river_borders(rivertype)
  66. int rivertype;
  67. {
  68.     int j, x, y, dir, elev, x1, y1, d1, e1, x2, y2, d2, e2;
  69.     int x0, y0, numrivers = 0, numrivs, numtouches;
  70.     int low, lowdir;
  71.     int t, watery[MAXTTYPES];
  72.     Feature *rfeat;
  73.  
  74.     announce_lengthy_process("Creating rivers (as borders)");
  75.     allocate_area_aux_terrain(rivertype);
  76.     if (DebugRiver)
  77.       init_features();
  78.     for_all_interior_cells(x0, y0) {
  79.     if (xrandom(10000) < t_river_chance(terrain_at(x0, y0))) {
  80.         ++numrivers;
  81.         touchedwater = FALSE;
  82.         if (numrivers % 5 == 0)
  83.           announce_progress((100 * numrivers) / totalrivers);
  84.         x = x0;  y = y0;
  85.         /* Set the initial river direction. */
  86.         lowdir = 0;
  87.         low = elev_at_meet(x, y, lowdir);
  88.         for_all_directions(dir) {
  89.         if (elev_at_meet(x, y, dir) < low) {
  90.             lowdir = dir;
  91.             low = elev_at_meet(x, y, lowdir); 
  92.         }
  93.         }
  94.         dir = lowdir;
  95.         /* If even the first bit of river is incompatible with the
  96.            surrounding terrain, blow this off and try the next location. */
  97.         if (!border_is_compatible(x, y, dir, rivertype))
  98.           continue;
  99.         /* Don't place this border if would join two other rivers;
  100.            detect by seeing river borders at both ends of this one. */
  101.         numtouches = 0;
  102.         if (point_in_dir(x, y, dir, &x1, &y1)) {
  103.         if (border_at(x, y, left_dir(dir), rivertype)
  104.             || border_at(x1, y1, right_dir(opposite_dir(dir)), rivertype))
  105.           ++numtouches;
  106.         if (border_at(x, y, right_dir(dir), rivertype)
  107.             || border_at(x1, y1, left_dir(opposite_dir(dir)), rivertype))
  108.           ++numtouches;
  109.         }
  110.         if (numtouches == 2)
  111.           continue;
  112.         set_river_at(x, y, dir, rivertype);
  113.         if (DebugRiver) {
  114.             char *featname;
  115.             Feature *feat;
  116.  
  117.             sprintf(spbuf, "src%d%s", numrivers, dirnames[dir]);
  118.             featname = copy_string(spbuf);
  119.             feat = create_feature("source", featname);
  120.             feat->size = 1;
  121.             set_raw_feature_at(x, y, feat->id);
  122.  
  123.             sprintf(spbuf, "riv#%d", numrivers);
  124.             featname = copy_string(spbuf);
  125.             rfeat = create_feature("river", featname);
  126.             rfeat->size = 0;
  127.         }
  128.         /* If our new bit of river already touches an existing river, just
  129.            stop now. */
  130.         if (numtouches == 1)
  131.           continue;
  132.         for (j = 0; j < area.maxdim; ++j) {
  133.         if (!inside_area(x, y))
  134.           break;
  135.         elev = elev_at_meet(x, y, dir);
  136.         /* Compute cell and dir of the two possible ways to flow. */
  137.         point_in_dir(x, y, right_dir(dir), &x1, &y1);
  138.         d1 = left_dir(dir);
  139.         e1 = elev_at_meet(x1, y1, d1);
  140.         x2 = x;  y2 = y;
  141.         d2 = right_dir(dir);
  142.         e2 = elev_at_meet(x2, y2, d2);
  143.         if (elev < e1 && elev < e2) {
  144.             init_warning("river going uphill??");
  145.             break;
  146.         }
  147.         /* Pick the lower of the two. */
  148.         if (e1 < e2) {
  149.             x = x1;  y = y1;  dir = d1;
  150.         } else {
  151.             x = x2;  y = y2;  dir = d2;
  152.         }
  153.         /* Don't add if might be between two edge cells. */
  154.         if (!inside_area(x, y))
  155.           break;
  156.         /* Rivers always follow the same paths, so if we see a river
  157.            here already, we're done. */
  158.         if (border_at(x, y, dir, rivertype))
  159.           break;
  160.         /* Make an actual piece of the river. */
  161.         if (border_is_compatible(x, y, dir, rivertype)) {
  162.             set_river_at(x, y, dir, rivertype);
  163.             if (DebugRiver && rfeat != NULL && raw_feature_at(x, y) == 0) {
  164.                 set_raw_feature_at(x, y, rfeat->id);
  165.                 ++(rfeat->size);
  166.             }
  167.         }
  168.         }
  169.         rfeat = NULL;
  170.     }
  171.     }
  172.     /* Cells surrounded by river should maybe be set specially. */
  173.     if (g_river_sink_terrain() != NONTTYPE) {
  174.     for_all_cells(x, y) {
  175.         if (inside_area(x, y)) {
  176.         numrivs = 0;
  177.         for_all_directions(dir) {
  178.             if (border_at(x, y, dir, rivertype)) ++numrivs;
  179.         }
  180.         if (numrivs >= NUMDIRS) {
  181.             set_terrain_at(x, y, g_river_sink_terrain());
  182.         }
  183.         }
  184.     }
  185.     }
  186.     /* Fix any bad adjacencies that got through. */
  187.     for_all_terrain_types(t) {
  188.         watery[t] = t_liquid(t);
  189.     }
  190.     for_all_interior_cells(x, y) {
  191.         if (watery[(int) terrain_at(x, y)]) {
  192.         for_all_directions(dir) {
  193.             set_border_at(x, y, dir, rivertype, FALSE);
  194.         }
  195.         }
  196.     }
  197.     finish_lengthy_process();
  198. }
  199.  
  200. static int
  201. border_is_compatible(x, y, dir, b)
  202. int x, y, dir, b;
  203. {
  204.     int x1, y1;
  205.  
  206.     return (tt_adj_terr_effect(terrain_at(x, y), b) < 0
  207.             && point_in_dir(x, y, dir, &x1, &y1)
  208.         && tt_adj_terr_effect(terrain_at(x1, y1), b) < 0);
  209. }
  210.  
  211. static int
  212. elev_in_dir(x, y, dir)
  213. int x, y, dir;
  214. {
  215.     int x1, y1;
  216.  
  217.     if (point_in_dir(x, y, dir, &x1, &y1)) {
  218.     return elev_at(x1, y1);
  219.     } else {
  220.     /* It's possible that the algorithm will ask for the elevation
  221.        of a point not in the area, but it's an obscure case, and
  222.        doesn't hurt to return an arbitrary elevation. */
  223.     return 0;
  224.     }
  225. }
  226.  
  227. /* The elevation at the junction of three cells is the lowest of the three. */
  228.  
  229. static int
  230. elev_at_meet(x, y, dir)
  231. int x, y, dir;
  232. {
  233.     int elev = elev_at(x, y);
  234.  
  235.     if (elev_in_dir(x, y, dir) < elev)
  236.       elev = elev_in_dir(x, y, dir);
  237.     if (elev_in_dir(x, y, right_dir(dir)) < elev)
  238.       elev = elev_in_dir(x, y, right_dir(dir));
  239.     return elev;
  240. }
  241.  
  242. /* should have various conditions */
  243.  
  244. static void
  245. set_river_at(x, y, dir, t)
  246. int x, y, dir, t;
  247. {
  248.     int x1, y1;
  249.  
  250.     if (touchedwater) {
  251.     } else if (t_liquid(terrain_at(x, y))) {
  252.     touchedwater = TRUE;
  253.     } else if (point_in_dir(x, y, dir, &x1, &y1)
  254.            && t_liquid(terrain_at(x1, y1))) {
  255.     touchedwater = TRUE;
  256.     } else {
  257.     set_border_at(x, y, dir, t, TRUE);
  258.     }
  259. }
  260.  
  261. static void
  262. make_up_river_connections(rivertype)
  263. int rivertype;
  264. {
  265.     int x0, y0, i, x, y, x1, y1, dir;
  266.     int numrivers = 0, lowdir, lowx, lowy, low;
  267.     
  268.     allocate_area_aux_terrain(rivertype);
  269.     announce_lengthy_process("Creating rivers (as connections)");
  270.     for_all_interior_cells(x0, y0) {
  271.     if (probability(t_river_chance(terrain_at(x0, y0)) / 100)) {
  272.         ++numrivers;
  273.         if (numrivers % 5 == 0)
  274.           announce_progress((100 * numrivers) / totalrivers);
  275.         x = x0;  y = y0;
  276.         for (i = 0; i < 20; ++i) {
  277.         /* Find the direction to the lowest adjacent cell. */
  278.         lowdir = -1;
  279.         low = elev_at(x, y);
  280.         for_all_directions(dir) {
  281.             if (point_in_dir(x, y, dir, &x1, &y1)) {
  282.             if (elev_at(x1, y1) <= low) {
  283.                 lowx = x1;  lowy = y1;
  284.                 lowdir = dir;
  285.                 low = elev_at(x1, y1);
  286.             }
  287.             }
  288.         }
  289.         if (lowdir < 0) break;
  290.         if (!(t_liquid(terrain_at(x, y))
  291.               && t_liquid(terrain_at(lowx, lowy)))) {
  292.             set_connection_at(x, y, lowdir, rivertype, TRUE);
  293.         }
  294.         x = lowx;  y = lowy;
  295.         if (!inside_area(x, y)) break;
  296.         }
  297.     }
  298.     }
  299.     finish_lengthy_process();
  300. }
  301.